// This code is licensed under New BSD Licence. For details see project page at
// http://code.google.com/p/hrissan-cocoa-helpers/source/checkout
#import "FileDownloader.h"

@implementation FileDownloader

+(FileDownloader*) create_with:(NSString *)url path:(NSString *)path delegate:(NSObject<FileDownloaderDelegate>*) delegate
{
	NSFileManager * manager = [NSFileManager defaultManager];
/*	if( ![manager fileExistsAtPath:path] )
	{
		NSString * fpath = [path stringByDeletingLastPathComponent];
		BOOL isDir;
		if( ![manager fileExistsAtPath:fpath isDirectory:&isDir] )
		{
			NSError * error;
			if( ![manager createDirectoryAtPath:fpath withIntermediateDirectories:YES attributes:nil error:&error] )
				return nil;
		}
	}*/
	
	
	NSFileHandle * file = [NSFileHandle fileHandleForWritingAtPath:path];
	if(file == nil)
	{
		[manager createFileAtPath:path contents:nil attributes:nil];
		file = [NSFileHandle fileHandleForWritingAtPath:path];
		if(file == nil)		
			return nil;
	}

	[file seekToEndOfFile];
	long long off = [file offsetInFile];

	NSMutableURLRequest * request = [[[NSMutableURLRequest alloc] init] autorelease];
	[request setURL:[NSURL URLWithString: url]];
	[request setHTTPMethod:@"GET"];
	[request setValue:@"*/*" forHTTPHeaderField:@"Accept"];
//	[request setValue:@"no-cache" forHTTPHeaderField:@"Pragma"];
	[request setValue:[NSString stringWithFormat:@"bytes=%@-", [NSString stringWithFormat:@"%lld", off]] forHTTPHeaderField:@"Range"];
	[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
	return [[[FileDownloader alloc] initWithURL:url request:request file:file delegate:delegate] autorelease];
}
	
-(id) initWithURL:(NSString *)_url request:(NSURLRequest *) request file:(NSFileHandle *)_file delegate:(NSObject<FileDownloaderDelegate>*)_delegate
{
	if(self = [super init])
	{
		url = _url;
		delegate = _delegate;//[l retain];
		file = _file;
		conn = [[[NSURLConnection alloc] initWithRequest:request delegate: self] autorelease];
		start_network_indicator();
		expected_size = -1;
		offset = [file.get() offsetInFile];
	}
	return self;
}

-(void) dealloc
{
//	[self close];
//	[listener release]; listener = nil;
	[super dealloc];
}

-(void) cancel
{
	if( !conn.get() )
		return;
	stop_network_indicator();
	[conn.get() cancel];
	[file.get() closeFile];
	conn = 0;
	file = 0;
}

-(long long)offset {
	return offset;
}

-(long long)expected_size {
	return expected_size;
}

-(NSString *)url {
	return url.get();
}


-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
//	NSLog(@"==== DownloadFile: didReceiveResponse content-length: %@, status-code: %@", 
//		  [NSString stringWithFormat:@"%ld", [response expectedContentLength]],
//		  [NSString stringWithFormat:@"%d", [response statusCode]]);
//	NSDictionary * fields = [response allHeaderFields];
//	for (id key in fields)
//		NSLog(@"key: %@, value: %@", key, [fields objectForKey:key]);

	int code = [response statusCode];

	if(code == 416)
	{
		expected_size = [file.get() offsetInFile];
		[delegate on_complete_download:self];
		[self cancel];
		return;
	}
	
	if(code >= 300)
	{
		[delegate on_error_download: self error:nil];
		[self cancel];
		return;
	}

	if(code == 200)
	{
		[file.get() truncateFileAtOffset:0];
	}

	offset = [file.get() offsetInFile];
	long long cl = [response expectedContentLength];
	if( cl != NSURLResponseUnknownLength )
		expected_size = offset + cl;

	[delegate on_start_download:self];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	long long prev_offset = offset;
	[file.get() writeData: data];
	offset = [file.get() offsetInFile];
	long long count_writed = offset - prev_offset;
	if([data length] != count_writed)
	{
		[self cancel];
		[delegate on_write_error:self];
		return;
	}
	[delegate on_progress_download:self];
	return;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//	if(connection != conn)
//		return;
	[self cancel];
	[delegate on_complete_download:self];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//	NSLog(@"Download data failed! Error - %@ %@", [error localizedDescription], [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
	[self cancel];
	[delegate on_error_download: self error:error];
}

- (NSString *)description {
	return [NSString stringWithFormat:@"FileDownloader URL: %@, expected size: %dl, offset: %dl", url.get(), expected_size, offset];
}

@end
